package com.css.filter;

import cn.hutool.json.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.css.entity.AdminUser;
import com.css.mapper.OAuth2AccessTokenMapper;
import com.css.oauth2.OAuth2AccessTokenDO;
import com.css.service.UserService;
import com.css.utils.JsonUtils;
import com.css.utils.LocalDateTimeUtils;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.micrometer.core.instrument.util.StringUtils;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.List;

/**
 * @author Dbj
 * @date 2024年09月30日  14:08
 */
@Component
public class TokenCheckFilter implements GlobalFilter, Ordered {

    private static ObjectMapper objectMapper = new ObjectMapper();

    @Resource
    private StringRedisTemplate stringRedisTemplate;
    @Resource
    UserService userService;
    @Resource
    OAuth2AccessTokenMapper oAuth2AccessTokenMapper;

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        System.out.println("11111111111111111");
        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response = exchange.getResponse();
        //校验
        //拿到请求头
        HttpHeaders headers = request.getHeaders();
        List<String> authorization = headers.get("Authorization");
        if (!CollectionUtils.isEmpty(authorization)) {
            String token = authorization.get(0);
            //token不空
            if (StringUtils.isNotBlank(token)){
//                OAuth2AccessTokenDO oAuth2AccessTokenDO = this.get(token);
//                if(oAuth2AccessTokenDO==null){
                    // 获取不到，从 MySQL 中获取
                    LambdaQueryWrapper<OAuth2AccessTokenDO> lambdaQueryWrapper = new LambdaQueryWrapper<>();
                    token = token.replace("Bearer ","");
                    lambdaQueryWrapper.eq(OAuth2AccessTokenDO::getAccessToken,token);
                    OAuth2AccessTokenDO oAuth2AccessTokenDO = oAuth2AccessTokenMapper.selectOne(lambdaQueryWrapper);
                    if(oAuth2AccessTokenDO==null){
                        return out(response,HttpStatus.UNAUTHORIZED.value(),"访问令牌异常");
                    }
                //}

                LocalDateTime now = LocalDateTime.now();
                if (now.isAfter(LocalDateTimeUtils.buildTime(oAuth2AccessTokenDO.getExpiresTime()))) {
                    return out(response,HttpStatus.UNAUTHORIZED.value(), "访问令牌异常");
                }
                Long userId = oAuth2AccessTokenDO.getUserId();
                AdminUser user = userService.getById(userId);
                if(ObjectUtils.isNotEmpty(user)){
                    String divisionCode = user.getDivisionCode();
                    // 重写请求头，方便业务系统从请求头获取用户id进行权限相关处理
                    ServerHttpRequest.Builder builder = exchange.getRequest().mutate();
//                    request = builder.headers(httpHeaders ->{
//                        headers.set("divisionCode", divisionCode);
//                        headers.set("userId", String.valueOf(userId));
//                    }).build();
                    request = builder.header("divisionCode", divisionCode+"_"+userId).build();
//                    request.getHeaders().set("userId", String.valueOf(userId));
                }
                System.out.println("身份请求验证成功");
                return chain.filter(exchange);
            }
        }else{
            ServerHttpRequest.Builder builder = exchange.getRequest().mutate();
            request = builder.header("divisionCode", "root"+"_123").build();
            return chain.filter(exchange);
        }
        return out(response,HttpStatus.UNAUTHORIZED.value(),"访问令牌异常");
    }

    @Override
    public int getOrder() {
        return 0;
    }

    private  String formatKey(String accessToken) {
        return String.format("oauth2_access_token:%s", accessToken);
    }
    public OAuth2AccessTokenDO get(String accessToken) {
        try {
            accessToken = accessToken.replace("Bearer","").trim();
            String redisKey = formatKey(accessToken);
            return JsonUtils.parseObject(stringRedisTemplate.opsForValue().get(redisKey), OAuth2AccessTokenDO.class);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    //如果权限没有通过,则返回具体的业务提示
    private Mono<Void> out(ServerHttpResponse resp, Integer code, String msg) {
        JSONObject jsonObject =  new JSONObject();
        jsonObject.put("code",code);
        jsonObject.put("msg",msg);
        DataBuffer buffer = null;
        try{
            byte[] bytes = jsonObject.toString().getBytes("UTF-8");
            buffer = resp.bufferFactory().wrap(bytes);
            resp.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
        }catch(Exception ex){
            ex.printStackTrace();
        } finally {
            return resp.writeWith(Mono.just(buffer));
        }
    }
}
